package com.yzcrm.erp.finance.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.aop.Aop;
import com.jfinal.aop.Before;
import com.jfinal.aop.Inject;
import com.jfinal.kit.Kv;
import com.jfinal.log.Log;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.activerecord.tx.TxSerializable;
import com.yzcrm.common.config.exception.YzcrmException;
import com.yzcrm.common.config.paragetter.BasePageRequest;
import com.yzcrm.common.constant.BaseConstant;
import com.yzcrm.erp.admin.entity.AdminField;
import com.yzcrm.erp.admin.entity.AdminScene;
import com.yzcrm.erp.admin.service.AdminExamineRecordService;
import com.yzcrm.erp.admin.service.AdminFieldService;
import com.yzcrm.erp.admin.service.AdminSceneService;
import com.yzcrm.erp.admin.service.AdminUserService;
import com.yzcrm.erp.crm.common.CheckStatusEnum;
import com.yzcrm.erp.crm.common.CrmEnum;
import com.yzcrm.erp.crm.service.CrmRecordService;
import com.yzcrm.erp.finance.entity.FinancePurchase;
import com.yzcrm.erp.finance.entity.FinancePurchaseDetail;
import com.yzcrm.utils.BaseUtil;
import com.yzcrm.utils.ParamsUtil;
import com.yzcrm.utils.R;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author jiang.xue
 */
public class FinancePurchaseService {

    @Inject
    private CrmRecordService crmRecordService;

    @Inject
    private AdminFieldService adminFieldService;

    @Inject
    private AdminSceneService adminSceneService;

    @Inject
    private AdminExamineRecordService examineRecordService;

    /**
     * 采购
     * @param jsonObject
     * @return
     */
    @Before(TxSerializable.class)
    public R addOrUpdate(JSONObject jsonObject) {

        Log.getLog(getClass()).info(jsonObject.toString());

        FinancePurchase financePurchase = jsonObject.getObject("entity", FinancePurchase.class);
        if(ObjectUtil.isNull(financePurchase)) {
            return R.error("参数不正确");
        }

        // 获取label
        CrmEnum crmEnum = CrmEnum.parse(financePurchase.getLabel());
        String realm = crmEnum.getName();
        if(ObjectUtil.isNull(realm)) {
            return R.error("label不存在");
        }

        JSONArray jsonArrayProducts = jsonObject.getJSONArray("products");
        if (ObjectUtil.isNull(jsonArrayProducts) || jsonArrayProducts.size() == 0) {
            return R.error("请添加要采购的产品");
        }

//        // 审核状态设置
//        if (ObjectUtil.isNotNull(financePurchase.getCheckStatus() )
//                && financePurchase.getCheckStatus() == CheckStatusEnum.CHECK_STATUS_DRAFT.getType()) {
//        } else {
//            financePurchase.setCheckStatus(CheckStatusEnum.CHECK_STATUS_WAIT.getType());
//        }

        String batchId = StrUtil.isNotEmpty(financePurchase.getBatchId()) ? financePurchase.getBatchId() : IdUtil.simpleUUID();
        adminFieldService.save(jsonObject.getJSONArray("field"), batchId);
        boolean flag;
        if(financePurchase.getPurchaseId() != null){
            // 更新

            crmRecordService.updateRecord(jsonObject.getJSONArray("field"), batchId);

            FinancePurchase oldFinancePurchase = FinancePurchase.dao.findById(financePurchase.getPurchaseId());
            if(ObjectUtil.isNull(oldFinancePurchase)) {
                throw new YzcrmException("要修改的采购信息不存在，无法编辑");
            }

            // 审核拒绝，已撤回，草稿能够修改
            if(oldFinancePurchase.getCheckStatus() != CheckStatusEnum.CHECK_STATUS_REJECTED.getType()
                    && oldFinancePurchase.getCheckStatus() != CheckStatusEnum.CHECK_STATUS_UNDO.getType()
                    && oldFinancePurchase.getCheckStatus() != CheckStatusEnum.CHECK_STATUS_DRAFT.getType()) {
                CheckStatusEnum checkStatusEnum = CheckStatusEnum.parse(oldFinancePurchase.getCheckStatus());
                throw new YzcrmException("采购信息"+checkStatusEnum.getRemarks()+"，无法编辑，请先撤回再编辑");
            }

            // 更新审核信息
            Map<String, Integer> map = examineRecordService.saveExamineRecord(
                    financePurchase.getLabel(),
                    jsonObject.getLong("checkUserId"),
                    oldFinancePurchase.getOwnerUserId(),
                    oldFinancePurchase.getExamineRecordId(),
                    financePurchase.getCheckStatus());
            if (map.get("status") == 0) {
                throw new YzcrmException("没有启动的审核步骤，不能添加！");
            } else {
                financePurchase.setExamineRecordId(map.get("id"));
            }

            if (financePurchase.getCheckStatus() != null && financePurchase.getCheckStatus() == CheckStatusEnum.CHECK_STATUS_DRAFT.getType()) {
                financePurchase.setCheckStatus(CheckStatusEnum.CHECK_STATUS_DRAFT.getType());
            } else if(financePurchase.getCheckStatus() != null && financePurchase.getCheckStatus() == CheckStatusEnum.CHECK_STATUS_OK.getType()){
                //批量导入时
                financePurchase.setCheckStatus(CheckStatusEnum.CHECK_STATUS_OK.getType());
            } else{
                financePurchase.setCheckStatus(CheckStatusEnum.CHECK_STATUS_WAIT.getType());
            }


            financePurchase.setUpdateTime(DateUtil.date());
            financePurchase.setUpdateUserId(BaseUtil.getUser().getUserId());
            flag = financePurchase.update();

            crmRecordService.updateRecord(oldFinancePurchase, financePurchase, crmEnum);

            // 更新采购商品详情,删除原有的商品明细
            Integer count = Db.update(Db.getSql("finance.purchaseDetail.deleteByPurchaseId"), financePurchase.getPurchaseId());
            if (count <= 0) {
                throw new YzcrmException("采购申请失败，请刷新页面重新尝试操作");
            }

            // 增加新商品明细
            for (int i = 0; i < jsonArrayProducts.size(); i++) {

                JSONObject jsonObjectProduct = jsonArrayProducts.getJSONObject(i);
                FinancePurchaseDetail financePurchaseDetail = jsonObjectProduct.toJavaObject(FinancePurchaseDetail.class);

                financePurchaseDetail.setPurchaseDetailId(null);
                financePurchaseDetail.setPurchaseId(financePurchase.getPurchaseId());
                financePurchaseDetail.setCreateTime(DateUtil.date());
                financePurchaseDetail.setCreateUserId(BaseUtil.getUser().getUserId());
                financePurchaseDetail.setUpdateTime(DateUtil.date());
                boolean result = financePurchaseDetail.save();
                if(!result) {
                    throw new YzcrmException("产品详细保存失败");
                }
            }


        }else{
            // 增加

            financePurchase.setType(financePurchase.getLabel()); // type 和 label一样含义
            financePurchase.setCreateTime(DateUtil.date());
            financePurchase.setUpdateTime(DateUtil.date());
            financePurchase.setCreateUserId(BaseUtil.getUser().getUserId());
            financePurchase.setBatchId(batchId);
//            启用
            financePurchase.setStatus(1);
            financePurchase.setOwnerUserId(BaseUtil.getUser().getUserId());

            // 增加审核
            Map<String, Integer> map = examineRecordService.saveExamineRecord(
                    financePurchase.getLabel(),
                    jsonObject.getLong("checkUserId"),
                    financePurchase.getOwnerUserId(),
                    null,
                    financePurchase.getCheckStatus()
            );
            if (map.get("status") == 0) {
                throw new YzcrmException("没有启动的审核步骤，不能添加！");

            } else {
                financePurchase.setExamineRecordId(map.get("id"));
            }

            if (financePurchase.getCheckStatus() != null && financePurchase.getCheckStatus() == CheckStatusEnum.CHECK_STATUS_DRAFT.getType()) {
                financePurchase.setCheckStatus(CheckStatusEnum.CHECK_STATUS_DRAFT.getType());
            } else if(financePurchase.getCheckStatus() != null && financePurchase.getCheckStatus() == CheckStatusEnum.CHECK_STATUS_OK.getType()){
                //批量导入时
                financePurchase.setCheckStatus(CheckStatusEnum.CHECK_STATUS_OK.getType());
            } else{
                financePurchase.setCheckStatus(CheckStatusEnum.CHECK_STATUS_WAIT.getType());
            }

            flag = financePurchase.save();
            crmRecordService.addRecord(financePurchase.getPurchaseId(), crmEnum);

            // 增加采购商品详情
            for (int i = 0; i < jsonArrayProducts.size(); i++) {

                JSONObject jsonObjectProduct = jsonArrayProducts.getJSONObject(i);
                FinancePurchaseDetail financePurchaseDetail = jsonObjectProduct.toJavaObject(FinancePurchaseDetail.class);

                financePurchaseDetail.setPurchaseId(financePurchase.getPurchaseId());
                financePurchaseDetail.setCreateTime(DateUtil.date());
                financePurchaseDetail.setCreateUserId(BaseUtil.getUser().getUserId());
                financePurchaseDetail.setUpdateTime(DateUtil.date());
                boolean result = financePurchaseDetail.save();
                if(!result) {
                    throw new YzcrmException("产品详细保存失败");
                }
            }
        }

        return flag ? R.ok().put("data", Kv.by("purchase_id", financePurchase.getPurchaseId())) : R.error();
    }

    /**
     * 获取场景 并 获取采购列表
     * @param basePageRequest
     * @return
     */
    public R filterConditionAndGetPageList(BasePageRequest basePageRequest){

        JSONObject jsonObject = basePageRequest.getJsonObject();
        Integer sceneId = jsonObject.getInteger("sceneId");
        JSONObject data = new JSONObject();
        if(sceneId != null && sceneId != 0){
            data = JSON.parseObject(AdminScene.dao.findById(sceneId).getData());
        }
        if(sceneId == null && jsonObject.getInteger("type") == 1){
            data = new JSONObject().fluentPut("is_transform", new JSONObject().fluentPut("name", "is_transform").fluentPut("condition", "is").fluentPut("value", "0"));
        }
        if(jsonObject.getJSONObject("data") != null){
            if(data != null){
                data.putAll(jsonObject.getJSONObject("data"));
            }
        }
        jsonObject.put("data",data);
        basePageRequest.setJsonObject(jsonObject);
        return getPurchasePageList(basePageRequest);
    }

    /**
     * 获取采购列表
     * @param basePageRequest
     * @return
     */
    public R getPurchasePageList(BasePageRequest basePageRequest) {
//    获取参数：type:54(采购)，该对象里面直接获取到getJsonObject
        JSONObject jsonObject = basePageRequest.getJsonObject();
//       类似创建一个Map,用来拼装参数
        Kv kv = new Kv();
//        创建list容器，用来存放返回的结果
        List<JSONObject> queryList = new ArrayList<>();
//        到里面的对象获取参数，jsonObject.getInteger("type")
        Integer type = jsonObject.getInteger("type");
        boolean isValid = jsonObject.getBoolean("isValid") != null ? jsonObject.getBoolean("isValid") : false;

        //自定义字段列表:也就是用户在填写申请表里面的字段，问题是携带什么参数去查呢？类型type
        Map<String, AdminField> fieldMap = adminSceneService.getAdminFieldMap(type);

        // 取得场景名称 同label
        String realm = CrmEnum.parse(type).getName();
        if(ObjectUtil.isNull(realm)) {
            return R.error("type不符合要求");
        }

        // 附加检索条件
        JSONObject data = basePageRequest.getJsonObject().getJSONObject("data");
        if (!adminSceneService.appendSqlCondition(kv, fieldMap, queryList, data, type)){
            return R.error("参数包含非法字段");
        }
        String search = basePageRequest.getJsonObject().getString("search");
        if(StrUtil.isNotEmpty(search)){
            if (!adminSceneService.appendSqlSearch(type, queryList, search)){
                return R.error("参数包含非法字段");
            }
            if(!kv.containsKey("fixed")){
                kv.set("fixed",true);
            }
        }

        // 获取排序字段
        String camelField = basePageRequest.getJsonObject().getString("sortField");
        String sortField = StrUtil.toUnderlineCase(camelField);
        String orderNum = basePageRequest.getJsonObject().getString("order");
        if(StrUtil.isEmpty(sortField) || StrUtil.isEmpty(orderNum)){
            kv.set("orderByKey", "update_time").set("orderByType", "desc").set("fieldType", 1);
        }else{
            if(! ParamsUtil.isValid(sortField)){
                return R.error("参数包含非法字段");
            }
            orderNum = "2".equals(orderNum) ? "asc" : "desc";
            kv.set("orderByKey", sortField).set("orderByType", orderNum).set("fieldType", fieldMap.get(sortField) != null ? fieldMap.get(sortField).getFieldType() : 0);
        }

        // 开始生成条件SQL
        StringBuilder conditions = new StringBuilder();

        //获取已审核数据
        if(isValid) {
            conditions.append(" and check_status = 1");
        }

        conditions.append(" and status != 2 ");
        conditions.append(" and label =  " + type);

        // 检索权限
        Long userId = BaseUtil.getUserId();
        List<Integer> roles = BaseUtil.getUser().getRoles();
        if(! BaseConstant.SUPER_ADMIN_USER_ID.equals(userId) && !roles.contains(BaseConstant.SUPER_ADMIN_ROLE_ID)){

            String menuRealm = "";
            if(type == CrmEnum.FINANCE_OFFICE_PURCHASE.getType() ) {
                menuRealm = "officePurchase";
            } else if(type == CrmEnum.FINANCE_NORMAL_PURCHASE.getType() ) {
                menuRealm = "normalPurchase";
            } else if(type == CrmEnum.FINANCE_PROJECT_PURCHASE.getType() ) {
                menuRealm = "projectPurchase";
            } else if(type == CrmEnum.FINANCE_DEV_PURCHASE.getType() ) {
                menuRealm = "devPurchase";
            } else if(type == CrmEnum.FINANCE_OTHER_PURCHASE.getType() ) {
                menuRealm = "otherPurchase";
            }

            List<Long> longs = Aop.get(AdminUserService.class).queryUserByAuth(userId, menuRealm);
            if(longs != null && longs.size() > 0){
                conditions.append(" and (a.owner_user_id in (").append(StrUtil.join(",", longs)).append(")");
                conditions.append(")");
            }
        }
        JSONObject sqlObject = new JSONObject();
        sqlObject.put("sql", conditions.toString());
        sqlObject.put("type", 1);
        if(!kv.containsKey("fixed")){
            kv.set("fixed",true);
        }
        queryList.add(sqlObject);

        // 设置分页
        if(StrUtil.isEmpty(basePageRequest.getJsonObject().getString("excel"))){
            kv.set("page", (basePageRequest.getPage() - 1) * basePageRequest.getLimit()).set("limit", basePageRequest.getLimit());
        }

        String selectSql = "select * ";
        List<String> batchList = adminSceneService.queryBatchId(queryList);
        if(batchList.size()==0&&kv.containsKey("field")){
            batchList.add("");
        }
        kv.set("select", selectSql).set("queryList", queryList).set("realm", realm).set("fieldMap", fieldMap).set("label", type);
        kv.set("batchList",batchList);
        SqlPara sqlPara = null;
        if(kv.getInt("fieldType") == 0){
            sqlPara = Db.getSqlPara("finance.purchase.queryPurchasePageList2", kv);
        }else{
            sqlPara = Db.getSqlPara("finance.purchase.queryPurchasePageList1", kv);
        }

        // 检索数据
        List<Record> recordPage = Db.find(sqlPara);

        // 检索采购明细
        recordPage.forEach(record -> {

            Integer purchaseId = record.get("purchaseId");
            List<Record> listFinancePurchaseDetail = Db.find(Db.getSql("finance.purchaseDetail.queryByPurchaseId"), purchaseId);
            record.set("listFinancePurchaseDetail", listFinancePurchaseDetail);

        });

        JSONObject resultJsonObject = new JSONObject();
        resultJsonObject.put("list", recordPage);
        SqlPara countSql = Db.getSqlPara("finance.purchase.queryPurchasePageListCount", kv);
        Integer count = Db.queryInt(countSql.getSql(), countSql.getPara());
        resultJsonObject.put("totalRow", count);
        return R.ok().put("data", resultJsonObject);

    }

    /**
     * @author wyq
     * 根据采购id查询
     */
    public Record queryById(Integer purchaseId){
        Record record = Db.findFirst(Db.getSql("finance.purchase.queryById"), purchaseId);
        List<Record> recordList = Db.find("select name,value from `yzcrm_admin_fieldv` where batch_id = ?", record.getStr("batch_id"));
        recordList.forEach(field -> record.set(field.getStr("name"), field.getStr("value")));
        return record;
    }

    /**
     * @author lg
     * 查询编辑字段
     */
    public List<Record> queryField(Integer purchaseId, Integer label){

        // 获取label
        CrmEnum crmEnum = CrmEnum.parse(label);

        Record purchase = queryById(purchaseId);
        List<Record> fieldList = adminFieldService.queryUpdateField(crmEnum.getType(), purchase);
        return fieldList;
    }

    /**
     * @author wyq
     * 根据id删除采购(审批通过的也可以删除)
     */
    @Before(TxSerializable.class)
    public R deleteByIds(String purchaseIds){

        String[] idsArr = purchaseIds.split(",");
        List<Record> idsList = new ArrayList<>();
        for(String id : idsArr){
            if(!BaseUtil.getUserId().equals(BaseConstant.SUPER_ADMIN_USER_ID) && !BaseUtil.getUser().getRoles().contains(BaseConstant.SUPER_ADMIN_ROLE_ID)){
                // TODO 测试时需要确认表是否加ro_user_id和rw_user_id && Db.queryInt(Db.getSql("crm.customer.queryIsRoUser"), BaseUtil.getUserId(), id) > 0
                return R.error("没有权限");
            }
            Record record = new Record();
            idsList.add(record.set("purchase_id", Integer.valueOf(id)));
        }

        List<Record> batchIdList = Db.find(Db.getSqlPara("finance.purchase.queryBatchIdByIds", Kv.by("ids", idsArr)));
        return Db.tx(() -> {
            Db.batch(Db.getSql("finance.purchase.deleteByIds"), "purchase_id", idsList, 100);
//            Db.batch("delete from yzcrm_admin_fieldv where batch_id = ?", "batch_id", batchIdList, 100);

            // 删除明细和采购
            for (int i = 0; i < idsList.size(); i++) {

                Record record = idsList.get(i);
                Integer purchaseId = record.get("purchase_id");

                // 刪除明细
                Db.update(Db.getSql("finance.purchaseDetail.deleteByPurchaseId"), purchaseId);

            }

            return true;
        }) ? R.ok() : R.error();
    }

    /**
     * @author wyq
     * 基本信息
     */
    public List<Record> information(Integer label, Integer purchaseId) {
        Record record = queryById(purchaseId);
        List<String> keyList = Arrays.asList("备注", "附件", "支付方式", "期望交付日期", "object_id", "申请理由");

        CrmEnum crmEnum = CrmEnum.parse(label);
        List<Record> recordList = adminFieldService.queryInformation(crmEnum, record, keyList);
        return recordList.stream().sorted(Comparator.comparingInt(r->-r.getInt("field_type"))).map(r-> r.remove("field_type","field_name","setting","type")).collect(Collectors.toList());
    }

    /**
     * 根据采购ID获取采购明细
     * @param purchaseId
     * @return
     */
    public List<Record> listPurchaseDetailByPurchaseId(Integer purchaseId) {

        // 检索采购详细信息
        List<Record> listFinancePurchaseDetail = Db.find(Db.getSql("finance.purchaseDetail.queryByPurchaseId"), purchaseId);

        return listFinancePurchaseDetail;
    }


    /**
     * 检索采购申请编号
     * @param purchaseNum
     * @param label
     * @return
     */
    public R queryPurchaseNum(String purchaseNum, Integer label) {

        Kv kv = Kv.by("purchaseNum", purchaseNum).set("label", label);

        // 检索采购申请编号
        List<Record> records = Db.find(Db.getSqlPara("finance.purchase.queryPurchaseNum", kv));

        // 检索采购明细
        records.forEach(record -> {

            Integer purchaseId = record.get("purchase_id");
            List<Record> listFinancePurchaseDetail = Db.find(Db.getSql("finance.purchaseDetail.queryByPurchaseId"), purchaseId);
            record.set("listFinancePurchaseDetail", listFinancePurchaseDetail);

            Log.getLog(FinancePurchase.class).info(purchaseId + " ++" +listFinancePurchaseDetail.size());

        });


        return R.ok().put("data", records);
    }

}
